package com.example.myapplication.thread;

import android.annotation.SuppressLint;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 几种常见的线程池的汇总
 */
public class ThreadPoolSum {

    private ExecutorService executor;

    public ThreadPoolSum() {
    }

    public ThreadPoolSum(ExecutorService executor) {
        this.executor = executor;
    }

    /**
     * 自定义线程
     * @return
     */
    public ExecutorService init(){
        executor = new ThreadPoolExecutor(
                10,
                20,
                60L,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue(10));
        return executor;
    }
    /**
     * 可缓存线程池
     *
     * 特点：newCachedThreadPool创建一个可缓存线程池，如果当前线程池的长度超过了处理的需要时，它可以灵活的回收空闲的线程，当需要增加时，
     * 它可以灵活的添加新的线程，而不会对池的长度作任何限制
     *
     * 缺点：它虽然可以无限的新建线程，但是容易造成堆外内存溢出，因为它的最大值是在初始化的时候设置为Integer.MAX_VALUE，
     * 一般来说机器都没那么大内存给它不断使用。当然知道可能出问题的点，就可以去重写一个方法限制一下这个最大值
     *
     * 总结：线程池为无限大，当执行第二个任务时第一个任务已经完成，会复用执行第一个任务的线程，而不用每次新建线程
     */
    public static void newCachedThreadPool(){
        System.out.println("------------------- 可缓存线程池 ------------------");
        // 创建无限大小线程池，由jvm自动回收
        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            newCachedThreadPool.execute(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(100);
                    } catch (Exception e) {

                    }
                    System.out.println(Thread.currentThread().getName() + ",i==" + temp);
                }
            });
        }
    }

    /**
     * 定长线程池
     *
     * 特点：创建一个定长线程池，可控制线程最大并发数，超出的线程会在队列中等待。定长线程池的大小最好根据系统资源进行设置。
     *
     * 缺点：线程数量是固定的，但是阻塞队列是无界队列。如果有很多请求积压，阻塞队列越来越长，容易导致OOM（超出内存空间）
     *
     * 总结：请求的挤压一定要和分配的线程池大小匹配，定线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()
     */
    public static void newFixedThreadPool(){
        System.out.println("------------------- 定长线程池 ------------------");
        ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            newFixedThreadPool.execute(new Runnable() {
                public void run() {
                    System.out.println(Thread.currentThread().getName() + ",i==" + temp);
                }
            });
        }
    }

    /**
     * 固定长度的线程池
     *
     * 特点：创建一个固定长度的线程池，而且支持定时的以及周期性的任务执行，类似于Timer（Timer是Java的一个定时器类）
     *
     * 缺点：由于所有任务都是由同一个线程来调度，因此所有任务都是串行执行的，同一时间只能有一个任务在执行，前一个任务的延迟或异常都将会影响到之后的任务（比如：一个任务出错，以后的任务都无法继续）
     */
    public static void newScheduledThreadPool(){
        System.out.println("------------------- 固定长度的线程池 ------------------");
        ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(3);
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            newScheduledThreadPool.schedule(new Runnable() {
                public void run() {
                    System.out.println("i:" + temp);
                }
            }, 3, TimeUnit.SECONDS);//这里表示延迟3秒执行。
        }
    }

    /**
     * 单线程化的线程池
     *
     * 特点：创建一个单线程化的线程池，它只会用唯一的工作线程来执行任务，如果这个唯一的线程因为异常结束，那么会有一个新的线程来替代它，他必须保证前一项任务执行完毕才能执行后一项。
     * 保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
     *
     * 缺点：缺点的话，很明显，他是单线程的，高并发业务下有点无力
     *
     * 总结：保证所有任务按照指定顺序执行的，如果这个唯一的线程因为异常结束，那么会有一个新的线程来替代它
     */
    public static void newSingleThreadExecutor(){
        ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            newSingleThreadExecutor.execute(new Runnable() {
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " index:" + index);
                    try {
                        Thread.sleep(200);
                    } catch (Exception e) {

                    }
                }
            });
        }
    }

    public synchronized static void main(String[] args) {
        newScheduledThreadPool();
        newCachedThreadPool();
        newSingleThreadExecutor();
        newFixedThreadPool();
    }

}
